package com.itheima.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.common.PageResult;
import com.itheima.dto.DishDto;
import com.itheima.entity.Category;
import com.itheima.entity.Dish;
import com.itheima.entity.DishFlavor;

import com.itheima.exception.BusinessException;
import com.itheima.mapper.DishMapper;
import com.itheima.service.CategoryService;
import com.itheima.service.DishFlavorService;
import com.itheima.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 菜品业务层接口实现类
 *
 * 注意：针对当前功能 菜品口味建立业务接口实现类，好处 如果业务比较复杂的时候，这个口味代码可以复用
 */
@Service
@Transactional
@Slf4j
public class DishServiceImpl implements DishService {
    @Autowired
    private DishMapper dishMapper;


    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 新增菜品
     *
     * @param dishDto
     */
    @Override
    public void saveWithFlavor(DishDto dishDto) {
        //1根据菜品名称查询菜品表
        LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dishLambdaQueryWrapper.eq(StringUtils.isNotEmpty(dishDto.getName()),Dish::getName,dishDto.getName());//菜品名称条件
        Integer count = dishMapper.selectCount(dishLambdaQueryWrapper);
        //2如果存在相同菜品名则提示用户菜品已经存在
        if(count>0){
            throw new BusinessException("菜品["+dishDto.getName()+"]已经存在了");
        }
        //3如果不存在相同菜品名称则插入菜品表
        dishMapper.insert(dishDto);
        //4.获取保存菜品表后主键id
        Long dishId = dishDto.getId();
        //5.循环菜品口味记录 往菜品口味表中插入
        List<DishFlavor> flavors = dishDto.getFlavors();
        //集合非空判断
        if(!CollectionUtils.isEmpty(flavors)){
            for (DishFlavor flavor : flavors) {
                flavor.setDishId(dishId);//菜品口味表中设置菜品id
                dishFlavorService.insert(flavor);
            }
        }
        //保存mysql 数据新增成功后 再清楚缓存数据
        //del dish_134234234_1
        String key = "dish_"+dishDto.getCategoryId()+"_"+dishDto.getStatus(); //dish_12324y32i473242_1
        redisTemplate.delete(key);
        log.debug("新增菜品后清除{}分类下菜品数据",dishDto.getCategoryId());
    }

    /**
     * 菜品分页查询
     *
     * @param page
     * @param pageSize
     * @param name
     */
    @Override
    public PageResult<DishDto> findPage(Long page, Long pageSize, String name) {
        // 2.1 new Page(page,pageSize)
        Page pp = new Page(page,pageSize);
        //2.1.1 添加name条件
        LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StringUtils.isNotEmpty(name),Dish::getName,name);//用户名
        //2.2 selectPage 进行分页
        dishMapper.selectPage(pp,lambdaQueryWrapper);
        //得到菜品分页集合数据
        List<Dish> records = pp.getRecords();
        //将List<Dish>集合转换为List<DishDto>
        List<DishDto> dishDtoList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(records)){
              dishDtoList = records.stream().map(
                    item -> {
                        DishDto dishDto = new DishDto();
                        //方式一：累的很
                        //dishDto.setName(item.getName());
                        //dishDto.setPrice(item.getPrice());
                        //方式二： 例如：A对象复制到B对象中 A对象中的属性名称以及类型 跟 B对象中的属性名称以及类型 一样才行
                        BeanUtils.copyProperties(item,dishDto);
                        Category category = categoryService.findById(item.getCategoryId());
                        dishDto.setCategoryName(category.getName());//DishDto 跟 Dish主要区别就是多一个分类名称
                        return dishDto;
                    }
            ).collect(Collectors.toList());
        }
        pp.setRecords(dishDtoList);//将转换后的 List<DishDto>设置Records属性上
        //2.3 将page对象中total records 封装到PageResult对象中
        log.debug("员工分页总记录数{}，当前页面数据{}",pp.getTotal(),pp.getRecords());
        return new PageResult<>(pp.getTotal(),pp.getRecords());
    }

    /**
     * 根据菜品主键id查询菜品数据（菜品表+菜品口味表数据）
     *
     * @param id
     */
    @Override
    public DishDto findById(Long id) {
        DishDto dishDto = new DishDto();
        //1先根据菜品主键id查询菜品表
        Dish dish = dishMapper.selectById(id);
        //2再根据菜品id查询菜品口味表
        List<DishFlavor> dishFlavorList = dishFlavorService.findById(id);
        //3.将dish菜品数据copy到DishDto
        BeanUtils.copyProperties(dish,dishDto);
        //4.将菜品口味数据设置到dishDto中
        dishDto.setFlavors(dishFlavorList);
        return dishDto;
    }

    /**
     * 修改菜品
     *
     * @param dishDto
     */
    @Override
    public void update(DishDto dishDto) {
        //1根据菜品名称查询菜品表
        //select * from dish where name = '麻婆豆腐' and id <> '1520980294545465345'
        LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dishLambdaQueryWrapper.eq(StringUtils.isNotEmpty(dishDto.getName()),Dish::getName,dishDto.getName());//菜品名称条件
        dishLambdaQueryWrapper.ne(Dish::getId,dishDto.getId());//排除自己 否则菜品名称没有修改的话 会提示已经存在
        Integer count = dishMapper.selectCount(dishLambdaQueryWrapper);
        //2如果存在相同菜品名则提示用户菜品已经存在
        if(count>0){
            throw new BusinessException("菜品["+dishDto.getName()+"]已经存在了");
        }
        //3根据菜品id更新菜品表
        dishMapper.updateById(dishDto);
        //4先根据菜品id删除菜品口味表数据
        dishFlavorService.deleteById(dishDto.getId());
        //5将修改的口味数据再插入菜品口味表中
        List<DishFlavor> flavors = dishDto.getFlavors();
        if(!CollectionUtils.isEmpty(flavors)){
            for (DishFlavor flavor : flavors) {
                flavor.setDishId(dishDto.getId());//菜品口味表 关联菜品id
                dishFlavorService.insert(flavor);
            }
        }
    }

    /**
     * 根据菜品分类id查询菜品列表数据
     *
     * @param dish
     */
    @Override
    //public List<Dish> list(Dish dish) {
    public List<DishDto> list(Dish dish) {
        //1查询redis菜品缓存数据是否存在   "dish_":业务标识
        String key = "dish_"+dish.getCategoryId()+"_"+dish.getStatus(); //dish_12324y32i473242_1
        String listDishDtoStr = (String)redisTemplate.opsForValue().get(key);
        //2.如果存在直接返回 将json string数据（listDishDtoStr） 转为 list集合
        if(StringUtils.isNotEmpty(listDishDtoStr)){
            log.debug("****查询菜品数据*******redis*******");
            return JSON.parseObject(listDishDtoStr,List.class);
        }
        //3.如果不存在查询数据库
        LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 参数1查询的字段  参数2：dish.getCategoryId()前端传入的参数值
        lambdaQueryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
        //根据菜品分类id查询菜品数据
        List<Dish> dishList = dishMapper.selectList(lambdaQueryWrapper);
        //根据菜品id查询口味数据
        //将List<Dish>转成List<DishDto>集合
        List<DishDto> dishDtoList = dishList.stream().map(
                myDish -> {
                    //创建DishDto对象
                    DishDto dishDto = new DishDto();
                    //1将myDish数据copy到dishDto
                    BeanUtils.copyProperties(myDish,dishDto);
                    //2dishDto缺数据到对应表中查询:菜品口味数据
                    //根据菜品id到dishFlavor表中查询菜品口味数据
                    List<DishFlavor> dishFlavorList = dishFlavorService.findById(myDish.getId());
                    //3.将dishFlavorList设置到DishDto中
                    dishDto.setFlavors(dishFlavorList);
                    return dishDto;
                }
        ).collect(Collectors.toList());
        //4.查询完数据库后，一定要将数据存入redis(如果不存 redis没数据 会一直会查询数据库)
        //将list集合 转为  json string数据
        redisTemplate.opsForValue().set(key,JSON.toJSONString(dishDtoList),24, TimeUnit.HOURS);
        log.debug("****查询菜品数据*******db*******");
        return dishDtoList;
    }

    /**
     * 菜品删除
     *
     * @param ids
     */
    @Override
    public void deleteByIds(List<Long> ids) {
        if (!CollectionUtils.isEmpty(ids)) {
            //1判断套餐是否在售
            for (Long dishId : ids) {
                //dishId套餐id
                LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                //条件 套餐id + 状态==1 （1：启售 0：停售）
                lambdaQueryWrapper.eq(Dish::getId, dishId);
                lambdaQueryWrapper.eq(Dish::getStatus, 1);//套餐是否是启售状态 如果是不能删除
                Dish dish = dishMapper.selectOne(lambdaQueryWrapper);
                //2如果在售 不能删除
                if (dish != null) {
                    throw new BusinessException("套餐[" + dish.getName() + "]启售中，不能删除");
                }
            }
            //3如果停售 则可以直接删除菜品
            dishMapper.deleteBatchIds(ids);
            log.debug("**删除菜品数据成功了**");

        }
    }

    /**
     * 根据id更新菜品状态
     */
    @Override
    public void updateStatus(Integer status,List<Long> ids) {


        LambdaUpdateWrapper<Dish> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Dish::getStatus,status)
                .in(Dish::getId,ids);
        dishMapper.update(null,updateWrapper);

    }
}
